package com.lxw.report.meta.query.dbpool;

import com.alibaba.druid.pool.DruidDataSource;
import com.lxw.report.meta.Exception.CommonException;
import com.lxw.report.meta.entity.DataBase;
import com.lxw.report.meta.enums.DbTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.sql.DataSource;


public class DruidDataSourcePool implements DataSourcePoolWrapper {
    private static Logger logger = LoggerFactory.getLogger(DataSourcePoolFactory.class);

    @Override
    public DataSource wrap( DataBase dataBase) throws CommonException {
        logger.info("begin DruidDataSourcePool create...");
        try {
             DruidDataSource dataSource = new DruidDataSource();
            //连接数据库的url，不同数据库不一样
            dataSource.setUrl(dataBase.getJdbcUrl());

            //连接数据库的用户名
            dataSource.setUsername(dataBase.getUser());

            //连接数据库的密码。
            dataSource.setPassword(dataBase.getPassword());

            //这一项可配可不配，如果不配置druid会根据url自动识别dbType，然后选择相应的driverClassName
            if(DbTypeEnum.getDriverByName(dataBase.getType())==null){
                throw new CommonException("未找到对应的数据库驱动："+ dataBase.getType());
            }
            dataSource.setDriverClassName(DbTypeEnum.getDriverByName(dataBase.getType()));

            //初始化时建立物理连接的个数。初始化发生在显示调用init方法，或者第一次getConnection时
            dataSource.setInitialSize(3);

            //最大连接池数量
            dataSource.setMaxActive(10);

            //最小连接池数量
            dataSource.setMinIdle(3);

            //获取连接时最大等待时间，单位毫秒。配置了maxWait之后，缺省启用公平锁，并发效率会有所下降，
            // 如果需要可以通过配置useUnfairLock属性为true使用非公平锁。
            //dataSource.setMaxWait(MapUtils.getInteger(rptDs.getOptions(), "maxWait", 60000));

            //1) Destroy线程会检测连接的间隔时间
            //testWhileIdle的判断依据，详细看testWhileIdle属性的说明
            dataSource.setTimeBetweenEvictionRunsMillis(60000);

            //连接保持空闲而不被驱逐的最长时间
            dataSource.setMinEvictableIdleTimeMillis(1800000);

            //用来检测连接是否有效的sql，要求是一个查询语句。如果validationQuery为null，testOnBorrow、testOnReturn、
            //testWhileIdle都不会其作用。
            dataSource.setValidationQuery("select 1");

            //建议配置为true，不影响性能，并且保证安全性。申请连接的时候检测，如果空闲时间大于timeBetweenEvictionRunsMillis，
            //执行validationQuery检测连接是否有效。
            dataSource.setTestWhileIdle(true);

            //申请连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能。
            dataSource.setTestOnBorrow(false);

            //归还连接时执行validationQuery检测连接是否有效，做了这个配置会降低性能
            dataSource.setTestOnReturn(false);

            //要启用PSCache，必须配置大于0，当大于0时，poolPreparedStatements自动触发修改为true。在Druid中，
            //不会存在Oracle下PSCache占用内存过多的问题，可以把这个数值配置大一些，比如说100
            dataSource.setMaxOpenPreparedStatements(20);

            //是否开启移除超时未归还连接的设置
            dataSource.setRemoveAbandoned(true);

            // 通过datasource.getConnontion() 取得的连接必须在removeAbandonedTimeout这么多秒内调用close(),
            // 要不我就弄死你.(就是conn不能超过指定的租期)
            dataSource.setRemoveAbandonedTimeout(1800);

            //关闭abanded连接(设置了超时时间未关闭)时输出错误日志
            dataSource.setLogAbandoned(true);
            return dataSource;
        } catch ( Exception ex) {
            throw new CommonException("连接池创建失败："+ ex.getMessage());
        }
    }
}
